#include "stdafx.h"

#include <DelayImp.h>
#include <AtlBase.h>
#include <AtlConv.h>

#include "UserInterface.h"

#include "../../Common/Interfaces/IPluginManager.h"
#include "../../Common/Interfaces/IEnvironment.h"
#include "../Direct3D9Hijack/Direct3D9Hijack.h"

//#include "../Common/dxstdafx.h" // DXUTgui


IServiceLocator* k_UserInterface::smr_ServiceLocator_ = NULL;

k_UserInterface::k_UserInterface()
	: mb_Activated(false)
	, mb_ActivationSwitchKeyDown(false)
	, mi_ModificatorKey(VK_SHIFT)
	, mi_Key(VK_SCROLL)
	, mh_GetMessageHook(0)
	, mb_Initialized(false)
	, mr_Device_(NULL)
	, mr_UiHandler_(NULL)
{
	HKEY lh_OpenedKey;
	if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Walhall\\Walhall", 0, KEY_READ, &lh_OpenedKey) == S_OK)
	{
		DWORD ldw_DataLength = MAX_PATH;
		BYTE lc_Data[MAX_PATH] = "";
		::RegQueryValueExA(lh_OpenedKey, "WalhallPath", 0, 0, lc_Data, &ldw_DataLength);
		::RegCloseKey(lh_OpenedKey);

		std::string ls_PathA = (char*)lc_Data;

		std::string ls_AntTweakbarDllPath = ls_PathA + "AntTweakBar.dll";

		::LoadLibraryA(ls_AntTweakbarDllPath.c_str());
	}
}


k_UserInterface::~k_UserInterface()
{
}


void* k_UserInterface::QueryInterface(const GUID& ar_InterfaceGuid)
{
	if (ar_InterfaceGuid == __uuidof(IUserInterface)) 
		return static_cast<IUserInterface*>(this);
	else if (ar_InterfaceGuid == __uuidof(IService)) 
		return static_cast<IService*>(this);

	return NULL; 
}


void k_UserInterface::Initialize(IServiceLocator& ar_ServiceLocator)
{
	smr_ServiceLocator_ = &ar_ServiceLocator;
	mb_Initialized = true;

	mr_Direct3DHijack_ = object_cast<IDirect3DHijack>(smr_ServiceLocator_);
}


void k_UserInterface::Deinitialize()
{
	this->set_Device(NULL);
	mb_Initialized = false;
}


bool k_UserInterface::get_IsInitialized() const
{
	return mb_Initialized;
}


IDirect3DDevice9* k_UserInterface::get_Device() const
{
	return mr_Device_;
}


void k_UserInterface::set_Device(IDirect3DDevice9* ar_Device_)
{
	IEnvironment& lr_Environment = object_cast<IEnvironment>(k_UserInterface::get_ServiceLocator());
	std::wstring ls_LogFile = lr_Environment.get_ModulePath()+L"Walhall.log";

	if (mr_Device_ == ar_Device_)
		return;

	if (mr_Device_ != NULL)
	{
		if (mh_GetMessageHook != 0)
			::UnhookWindowsHookEx(mh_GetMessageHook);
		mh_GetMessageHook = 0;

		if (mr_UiHandler_ != NULL)
			delete mr_UiHandler_;
		mr_UiHandler_ = NULL;

		::TwTerminate();
	}

	mr_Device_ = ar_Device_;

	if (mr_Device_ != NULL)
	{
		mh_GetMessageHook = SetWindowsHookEx(WH_GETMESSAGE, k_UserInterface::GetMessageProc, NULL, GetCurrentThreadId());

		::TwInit(TW_DIRECT3D9, mr_Device_);

		D3DDISPLAYMODE lr_DisplayMode;
		mr_Device_->GetDisplayMode(0, &lr_DisplayMode);
		::TwWindowSize(lr_DisplayMode.Width, lr_DisplayMode.Height);

		mr_UiHandler_ = new k_UiHandler(*smr_ServiceLocator_);

		mb_Initialized = true;
	}
}


void k_UserInterface::UpdateActivationState()
{
	bool lb_OldActivationSwitchKeyDown = mb_ActivationSwitchKeyDown;
	if (GetAsyncKeyState(mi_Key) & 0x8000)
	{
		mb_ActivationSwitchKeyDown = true;
	}
	else
		mb_ActivationSwitchKeyDown = false;

	if (mb_ActivationSwitchKeyDown && !lb_OldActivationSwitchKeyDown)
	{
		mb_Activated = !mb_Activated;
		if (mb_Activated)
		{
			LPDIRECT3DSURFACE9 lr_RendertargetSurface_;
			D3DSURFACE_DESC lr_RenderTargetDescription;

			mr_Device_->GetRenderTarget(0, &lr_RendertargetSurface_);
			lr_RendertargetSurface_->GetDesc(&lr_RenderTargetDescription);
			lr_RendertargetSurface_->Release();

			::TwWindowSize(lr_RenderTargetDescription.Width, lr_RenderTargetDescription.Height);

			mh_OldMouseCursor = ::GetCursor();
			::ShowCursor(true);
			::SetCursor(LoadCursor(NULL, IDC_ARROW));
		}
		else
		{
			::SetCursor(mh_OldMouseCursor);
			::ShowCursor(false);
		}
	}
}


bool k_UserInterface::ProcessUiMessage(HWND ah_Wnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	this->UpdateActivationState();

	if (uMsg == WM_SETCURSOR)
		return true;

	// Send event message to AntTweakBar
	if (mb_Activated)
	{
		if(::TwEventWin(ah_Wnd, uMsg, wParam, lParam))
			return true;
	}

	return false;
}


void k_UserInterface::RenderMenu()
{
	if (!mb_Activated || !mb_Initialized)
		return;

	::TwDraw();
}


HHOOK k_UserInterface::get_GetMessageHook() const
{
	return mh_GetMessageHook;
}


bool k_UserInterface::get_IsMenuModeActive() const
{
	return mb_Activated;
}


void k_UserInterface::set_MenuModeActiveState(bool ab_State)
{
	mb_Activated = ab_State;
}


IUiHandler* k_UserInterface::get_UiHandler() const
{
	return mr_UiHandler_;
}


void k_UserInterface::set_Active(bool ab_State)
{
	if (ab_State && !mb_Activated)
		while (ShowCursor(TRUE) <= 0);
	else if (!ab_State && mb_Activated)
		while (ShowCursor(FALSE) > 0);
	mb_Activated = ab_State;
}


bool k_UserInterface::get_Active() const
{
	return mb_Activated;
}


LRESULT k_UserInterface::GetMessageProc(int code, WPARAM wParam, LPARAM lParam)
{
	IServiceLocator& lr_SvLocator = k_Direct3D9Hijack::get_ServiceLocator();
	IUserInterface& lr_Ui = object_cast<IUserInterface>(lr_SvLocator);
	IPluginManager& lr_PluginManager = object_cast<IPluginManager>(lr_SvLocator);

	if (code < 0)
		return ::CallNextHookEx(lr_Ui.get_GetMessageHook(), code, wParam, lParam);
	
	MSG* lr_Msg_ = (MSG*)lParam;
	if (lr_Msg_->message == WM_QUIT)
	{
		IEnvironment& lr_Environment = object_cast<IEnvironment>(lr_SvLocator);
		std::wstring ls_LogFile = lr_Environment.get_ModulePath() + L"Walhall.log";

		lr_Ui.set_Device(NULL);
		lr_PluginManager.UnloadPlugins();
	}
	else
	{
		if (lr_Ui.ProcessUiMessage(lr_Msg_->hwnd, lr_Msg_->message, lr_Msg_->wParam, lr_Msg_->lParam))
			::ZeroMemory(lr_Msg_, sizeof(MSG));
	}

	return ::CallNextHookEx(lr_Ui.get_GetMessageHook(), code, wParam, lParam);
}
